/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

// yue soc 顶层模块
module yue_soc_top # (
    parameter SIM_DEBUG = "FALSE",
    
    parameter [ 31: 0 ] TMR_BASEADDR  = 32'h0200_0000,      // 软件中断寄存器
    parameter [ 31: 0 ] PLIC_BASEADDR = 32'h0c00_0000,      // 外部中断寄存器
    parameter [ 31: 0 ] ITCM_BASEADDR = 32'h8000_0000,      // ITCM 地址空间
    parameter [ 31: 0 ] DTCM_BASEADDR = 32'h9000_0000,      // DTCM 地址空间
    parameter [ 31: 0 ] UART_BASEADDR = 32'he000_0000,      // UART 基地址
    parameter [ 31: 0 ] GPIO_BASEADDR = 32'hf000_0000,      // GPIO 基地址

    parameter IO_WIDTHa = 8,
    parameter IO_WIDTHb = 6,
    parameter IO_WIDTHc = 8,
    parameter IO_WIDTHd = 4
)
(
    input  OSC_CLK,

    inout  [ IO_WIDTHa - 1: 0 ] LED,

    inout  [ IO_WIDTHb - 1: 0 ] SEAT,
    inout  [ IO_WIDTHc - 1: 0 ] SEG,

    inout  [ IO_WIDTHd - 1: 0 ] PB,
    input  PB_PROG,

    output UART_TXD,
    input  UART_RXD,

    inout  I2C_SDA,
    inout  I2C_SCL,

    output QSPI_SCK,
    output QSPI_CS,
    inout  [ 3: 0 ] QSPI_DQ,

    input  EXT_RSTN

);


//===============================================================================
wire sys_locked;
wire sys_clk;
wire pc_clk;
wire l_clk;
SYS_DCM HL_clk_inst
(
// Clock in ports
    .clk_in1    ( OSC_CLK ),
// Clock out ports
    .clk_out1   ( l_clk ),
    .clk_out2   ( sys_clk ),
    .clk_out3   ( pc_clk ),
// Status and control signals
//    .reset      ( !EXT_RSTN ),
    .reset      ( 1'b0 ),
    .locked     ( sys_locked )
);


//===============================================================================


reg [16:0] rst_r = 0;
always@( posedge sys_clk )
if( (sys_locked == 0) | (EXT_RSTN == 0)) rst_r <= 0;
else
begin 
    if( SIM_DEBUG == "FALSE")
    begin:real_dbg
        if(!rst_r[16])  rst_r <= rst_r + 1;
    end
    else    
    begin:sim_dbg
        if(!rst_r[7])  rst_r <= rst_r + 1;
    end
end
wire rst_n = ( SIM_DEBUG == "FALSE") ? rst_r[16] : rst_r[7];
//===============================================================================
wire [ 31: 0 ] gpio_ia;
wire [ 31: 0 ] gpio_oa;
wire [ 31: 0 ] gpio_ta;
wire [ 31: 0 ] gpio_a;

//fii_iobuf     #( .IO_WIDTH( IO_WIDTHa ) )
fii_iobuf #( .IO_WIDTH( 32 ) )
fii_iobuf_insta
(
    .i_dio_t    ( gpio_ta ),
    .i_dio      ( gpio_oa ),
    .o_dio      ( gpio_ia ),
    .io_dio_p   ( gpio_a )
//    .io_dio_p   ( LED )
);
assign LED = gpio_a[ IO_WIDTHa - 1: 0 ];

wire [ 31: 0 ] gpio_ib;
wire [ 31: 0 ] gpio_ob;
wire [ 31: 0 ] gpio_tb;
wire [ 31: 0 ] gpio_b;

fii_iobuf #( .IO_WIDTH( 32 ) )
fii_iobuf_instb
(
    .i_dio_t    ( gpio_tb ),
    .i_dio      ( gpio_ob ),
    .o_dio      ( gpio_ib ),
    .io_dio_p   ( gpio_b )
//    .io_dio_p   ( SEAT )
);
assign SEAT = gpio_b[ IO_WIDTHb - 1: 0 ];


wire [ 31: 0 ] gpio_ic;
wire [ 31: 0 ] gpio_oc;
wire [ 31: 0 ] gpio_tc;
wire [ 31: 0 ] gpio_c;

fii_iobuf #( .IO_WIDTH( 32 ) )
fii_iobuf_instc
(
    .i_dio_t    ( gpio_tc ),
    .i_dio      ( gpio_oc ),
    .o_dio      ( gpio_ic ),
    .io_dio_p   ( gpio_c )
//    .io_dio_p   ( SEG )
);
assign SEG = gpio_c[ IO_WIDTHc - 1: 0 ];


wire [ 31: 0 ] gpio_id;
wire [ 31: 0 ] gpio_od;
wire [ 31: 0 ] gpio_td;
wire [ 31: 0 ] gpio_d;

fii_iobuf #( .IO_WIDTH( 32 ) )
fii_iobuf_instd
(
    .i_dio_t    ( gpio_td ),
    .i_dio      ( gpio_od ),
    .o_dio      ( gpio_id ),
    .io_dio_p   ( gpio_d )
//    .io_dio_p   ( PB )
);
assign PB  = gpio_d[ 2: 0 ];
assign {I2C_SDA, I2C_SCL} = gpio_d[ 7: 6 ];

//===============================================================================
wire cpu_stop;
wire cpu_start;

// load software program from uart
(* mark_debug = "true" *)reg i_cpu_reset = 0;
always @ ( posedge sys_clk )
if ( !rst_n ) i_cpu_reset <= 0;
else
begin
    if ( cpu_stop ) i_cpu_reset <= 1;
    else if ( cpu_start ) i_cpu_reset <= 0;
end

//===============================================================================
wire txd_start;
wire [ 7: 0 ] txd_data;
wire txd_done;

wire [ 11: 0 ] code_addr;
wire [ 31: 0 ] code_din;
wire code_wea;


fii_riscv_cpu #(
    .TMR_BASEADDR  ( TMR_BASEADDR ),
    .PLIC_BASEADDR ( PLIC_BASEADDR ),
    .ITCM_BASEADDR ( ITCM_BASEADDR ),
    .DTCM_BASEADDR ( DTCM_BASEADDR ),
    .UART_BASEADDR ( UART_BASEADDR ),
    .GPIO_BASEADDR ( GPIO_BASEADDR )
)
fii_riscv_cpu_inst
(
    .sys_clk        ( sys_clk ),

// ============================================
    .i_GPIO_dina    ( gpio_ia ),
    .o_GPIO_douta   ( gpio_oa ),
    .o_GPIO_ta      ( gpio_ta ),

    .i_GPIO_dinb    ( gpio_ib ),
    .o_GPIO_doutb   ( gpio_ob ),
    .o_GPIO_tb      ( gpio_tb ),

    .i_GPIO_dinc    ( gpio_ic ),
    .o_GPIO_doutc   ( gpio_oc ),
    .o_GPIO_tc      ( gpio_tc ),

    .i_GPIO_dind    ( gpio_id ),
    .o_GPIO_doutd   ( gpio_od ),
    .o_GPIO_td      ( gpio_td ),
// ============================================
    .txd_start      ( txd_start ),
    .txd_data       ( txd_data ),
    .txd_done       ( txd_done ),
// ============================================
    .code_addr      ( code_addr ),
    .code_din       ( code_din ),
    .code_wea       ( code_wea ),
// ============================================
    .l_clk          ( l_clk ),

    .i_cpu_reset    ( i_cpu_reset ),
    .rst_n          ( rst_n )
);
//===============================================================================
DEBOUNCE_IN # ( .PIN_INIT( 1'b1 ) )
uart_start_inst
(
    .clk        ( sys_clk ),

    .pin_in     ( PB_PROG ),
    .pin_out    ( ),

    .pin_pos    ( ),
    .pin_neg    ( cpu_stop ),

    .rst_n      ( rst_n )
);
//===============================================================================
pc_uart #( .MAIN_CLK ( 50 ) ) 
pc_uart_inst
(
    .clk        ( sys_clk ),

    .rxd        ( UART_RXD ),
    .txd        ( UART_TXD ),

    .code_addr  ( code_addr ),
    .code_din   ( code_din ),
    .code_wea   ( code_wea ),

    .txd_start  ( txd_start ),
    .txd_data   ( txd_data ),
    .txd_done   ( txd_done ),

    .rxd_done   ( cpu_start ),

    .reset      ( cpu_stop | ( ~rst_n ) )
);





assign QSPI_SCK = 1'bz;
assign QSPI_CS = 1'b1;


endmodule
